// MAPIWrapper.cpp : Defines the entry point for the DLL application.
//

#include "stdafx.h"
#define MAPIWRAPPER_EXPORTS 1
#include "CMAPIWrapper.h"

#include <guiddef.h>
#include <ks.h>
#define INITGUID
#include <objbase.h>

#ifndef USES_IID_IMessage
#define USES_IID_IMessage
DEFINE_GUID(CLSID_MailMessage,0x00020D0B,0x0000, 0x0000, 0xC0, 0x00, 0x0, 0x00, 0x0, 0x00, 0x00, 0x46);

DEFINE_GUID(CLSID_EVENT,0x00062002,0x0000, 0x0000, 0xC0, 0x00, 0x0, 0x00, 0x0, 0x00, 0x00, 0x46);

#endif
#ifndef USES_PS_PUBLIC_STRINGS
#define USES_PS_PUBLIC_STRINGS
#endif

#ifndef USES_IID_IMAPIFolder
#define USES_IID_IMAPIFolder
#endif
#ifndef USES_IID_IMAPITable
#define USES_IID_IMAPITable
#endif
#include <mapix.h>
#include <mapitags.h>
#include <mapidefs.h>
#include <mapiutil.h>
#include <mapiguid.h>
#include <imessage.h>

#include <richedit.h>
#include <richole.h> 

/*#include "imnact.h"
#inc'lude "mapimimeex.h"*/
#include <mimeole.h>
#include <imnxport.h>

#include "mapimime.h"
#include "RichEditOLECallback.h"

#define NOMIMESUPPORT -1;
#define COULDNOTCREATESTREAM -2;
#define WRITEFILEFAILED -3;
#define EXPORTMAILMESSAGEFAILED -4;
#define CREATEFILEFAILED -5;
#define EXPORTEDWITHOLEERRORS -6;

DEFINE_GUID(CLSID_IConverterSession, 0x4e3a7680, 0xb77a, 0x11d0, 0x9d, 0xa5, 0x0, 0xc0, 0x4f, 0xd6, 0x56, 0x85); 
DEFINE_GUID(IID_IConverterSession, 0x4b401570, 0xb77b, 0x11d0, 0x9d, 0xa5, 0x0, 0xc0, 0x4f, 0xd6, 0x56, 0x85);


DEFINE_GUID(CLSID_OUTLOOKSET, 0x00020329, 0x0000, 0x0000, 0xC000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46);

static GUID const CLSID_StdOleLink = {0x00000300, 0x0000, 0x0000, {0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46} };

#define PR_OUTLOOK_EVENT_RECURRENCE_DATA		PROP_TAG( PT_BINARY,	0x815B)
#define PR_OUTLOOK_EVENT_IS_RECURRING			PROP_TAG( PT_BOOLEAN,	0x81AF)
HRESULT __fastcall UnicodeToAnsi(LPCOLESTR pszW, LPSTR* ppszA);
HRESULT __fastcall AnsiToUnicode(LPCSTR pszA, LPOLESTR* ppszW);


BOOL APIENTRY DllMain( HANDLE hModule, 
											DWORD  ul_reason_for_call, 
											LPVOID lpReserved
											)
{
	switch (ul_reason_for_call)
	{
	case DLL_PROCESS_ATTACH:
	case DLL_THREAD_ATTACH:
	case DLL_THREAD_DETACH:
	case DLL_PROCESS_DETACH:
		break;
	}
	return TRUE;
}

struct Foo
{
	HANDLE hFile;
} f;
static DWORD CALLBACK MyStreamOutCallback(DWORD dwCookie, LPBYTE pbBuff, LONG cb, LONG *pcb)
{
	struct Foo *param = (struct Foo *)dwCookie;
	DWORD dwWritten=0;
	WriteFile( param->hFile, pbBuff, cb, &dwWritten, NULL );

	*pcb = cb;

	return 0;
}
static DWORD CALLBACK 
MyStreamInCallback(DWORD dwCookie, LPBYTE pbBuff, LONG cb, LONG *pcb)
{
	LPSTREAM pStream = (LPSTREAM)dwCookie;
	
	DWORD dW=-1;
	if(pStream)
		pStream->Read(pbBuff,cb,&dW);
	*pcb=dW;
	return 0;
}
static DWORD CALLBACK 
MyStreamInCallback2(DWORD dwCookie, LPBYTE pbBuff, LONG cb, LONG *pcb)
{
	struct Foo *param = (struct Foo *)dwCookie;
	DWORD dW=0;
	ReadFile(param->hFile,pbBuff,cb,&dW,NULL);
	*pcb=dW;
	return 0;
}

int fnGetIdsFromNames(LPUNKNOWN pObject, LPWSTR name, int Type);

//void ErrorHandler(LPSTR szError)
//{
//}
//
//
//class CWriteOLEStreamToRTF : public OLESTREAM
//
//{
//
//public:
//
//    CWriteOLEStreamToRTF( HANDLE hFile )
//
//        : m_hFile( hFile )
//
//    {
//
//        lpstbl = &OLEStreamVtbl;
//
//        lpstbl->Get = NULL;
//
//        lpstbl->Put = (DWORD (CALLBACK* )(LPOLESTREAM, const void FAR*, DWORD)) WriteObjectToEditstream;
//
//    }
//
// 
//
//    static DWORD CALLBACK WriteObjectToEditstream( LPOLESTREAM pStream, const VOID *pvBuffer, DWORD cbBuffer )
//
//    {
//
//        static const CHAR      szHexDigits[] = "0123456789abcdef";
//
//        CWriteOLEStreamToRTF * pThis = (CWriteOLEStreamToRTF *)pStream;
//
//        CHAR                   szData[2];
//
//        LONG                   cb = 0;
//
//        DWORD                  dwWritten;
//
//        BYTE                   bT;        
//
//        LPBYTE                 pbBuffer = (LPBYTE)pvBuffer;
//
// 
//
//        while( cb < cbBuffer )
//
//        {
//
//            bT = *pbBuffer++;                       // Put out hex value of byte
//
//            szData[0] = szHexDigits[bT >> 4];       // Store high nibble
//
//            szData[1] = szHexDigits[bT & 15];       // Store low nibble
//
// 
//
//            // Write the data
//
//            WriteFile( pThis->m_hFile, &szData, 2, &dwWritten, NULL );
//						DWORD lastError=GetLastError();
//
// 
//
//            // Every 78 chars and at end of group, drop a line
//
//            if ( !(++cb % 39) || (cb == cbBuffer) )
//
//            {
//
//                CHAR szNewLine[] = "\r\n";
//
//                WriteFile( pThis->m_hFile, &szNewLine, 2, &dwWritten, NULL );
//
//            }
//
//        }
//
// 
//
//        return cb;
//
//    }
//
// 
//
//private:
//
//    OLESTREAMVTBL   OLEStreamVtbl;
//
//    HANDLE          m_hFile;
//
//};
//
// 
//
//HRESULT SaveIStorageToRTFFile( IStorage *pStorage, HANDLE hFile )
//
//{
//
//    HRESULT              hr;
//
//    CWriteOLEStreamToRTF obj( hFile );
//
// 
//
//    hr = OleConvertIStorageToOLESTREAM( pStorage, &obj );
//		//LPOLEOBJECT pOle;
//		//hr = OleLoad(&obj , &IID_IOleObject, pClientSite, ppvObj);
//		//if(SUCCEEDED(hr))
//		//{
//
//		//}
//
// 
//
//    return hr;
//
//}
//


HRESULT SaveToTxt( LPMESSAGE pMessage, char *strFileName )
{
	char *pBody=0;
	UINT nSize=0;
	IStream *pStream;



	HRESULT hRes = pMessage->OpenProperty(PR_BODY, &IID_IStream, STGM_READ, 0, (IUnknown**)&pStream);
	if(SUCCEEDED(hRes))
	{
		STATSTG stg = {0};
		hRes = pStream->Stat(&stg,STATFLAG_NONAME);
		if (SUCCEEDED(hRes))
		{ 
			nSize = stg.cbSize.LowPart; 
			pBody = new char[nSize+1];
			ULONG unRead; 
			hRes = pStream->Read(pBody, nSize, &unRead);
			if (FAILED(hRes))
			{ 
				nSize=0;
			}
			else if (unRead<nSize) 
				nSize=unRead;
			pBody[nSize]='\0';
		}
		pStream->Release();
		if(nSize>0)
		{
			HANDLE hFile; 

			hFile = CreateFile(strFileName,
				GENERIC_WRITE,                // open for writing 
				0,                            // do not share 
				NULL,                         // no security 
				CREATE_ALWAYS,                // overwrite existing 
				FILE_ATTRIBUTE_NORMAL,        // normal file 
				NULL);                        // no attr. template 
			if(hFile != INVALID_HANDLE_VALUE)
			{
				DWORD dWritten=0;
				if(!WriteFile(hFile,pBody,nSize,&dWritten,NULL))
					return 7;

				CloseHandle(hFile);

			}


		}
	}


	return hRes;

}

//HRESULT WriteAttachmentObjectToFile ( LPMESSAGE pMsg, LPSTORAGE *pStorage)
//{
//	SizedSPropTagArray(1,g_sptMsgProps) = {1,
//		PR_HASATTACH};
//
//	LPSPropValue pProps = NULL;
//	HRESULT hRes = 0;
//	ULONG cVals = 0;
//
//	if (FAILED(hRes = pMsg->GetProps((LPSPropTagArray) &g_sptMsgProps,
//		0,
//		&cVals,
//		&pProps)))
//		goto Quit;
//	else
//		hRes = S_OK;
//
//	if (PR_HASATTACH == pProps[0].ulPropTag && pProps[0].Value.b)
//	{
//		LPMAPITABLE pAttTbl = NULL;
//		LPSRowSet pRows = NULL;
//		static SizedSPropTagArray(2,sptCols) = {2, PR_ATTACH_METHOD,
//			PR_ATTACH_NUM};
//
//		if (SUCCEEDED(hRes = pMsg -> OpenProperty(PR_MESSAGE_ATTACHMENTS,
//			&IID_IMAPITable,
//			0,
//			0,
//			(LPUNKNOWN *) &pAttTbl)))
//		{
//
//			if (SUCCEEDED(hRes = pAttTbl -> SetColumns(
//				(LPSPropTagArray) &sptCols,
//				TBL_BATCH)))
//			{
//
//				if (SUCCEEDED(hRes = HrQueryAllRows(pAttTbl,
//					(LPSPropTagArray) &sptCols,
//					NULL,
//					NULL,
//					0,
//					&pRows)))
//				{
//
//					for (ULONG i = 0; i < pRows -> cRows; i++)
//					{
//						LPATTACH lpAttach = NULL;
//
//						// Verify we received a filename from GetProps
//						if (!  PR_ATTACH_METHOD ==
//							pRows->aRow[i].lpProps[0].ulPropTag)
//							break;
//
//						// Verify we received an Attachment Index from GetProps
//						if (! PR_ATTACH_NUM == pRows->aRow[i].lpProps[1].ulPropTag)
//							break;
//
//						// Open the attachment
//						if (SUCCEEDED(hRes = pMsg->OpenAttach (
//							pRows->aRow[i].lpProps[1].Value.l,
//							NULL, MAPI_BEST_ACCESS, &lpAttach)))
//						{
//
//
//							LPSTORAGE pDestStorage=NULL;
//
//							if(pRows->aRow[i].lpProps[0].Value.ul==ATTACH_OLE)
//							{
//
//								// Open the property of the attachment
//								// containing the file data
//								if (FAILED(hRes = lpAttach->OpenProperty(
//									PR_ATTACH_DATA_OBJ,
//									(LPIID)&IID_IStorage,
//									0,
//									MAPI_MODIFY,
//									(LPUNKNOWN *)&pStorage)))
//									break;
//								//Copy to the file system for test purposes
//								if(SUCCEEDED(hRes = StgCreateDocfile(L"C:\\1.bin",STGM_TRANSACTED|STGM_READWRITE|STGM_SHARE_EXCLUSIVE|STGM_CREATE,0,&pDestStorage)))
//								{
//
//
//									hRes = pStorage -> CopyTo(NULL,NULL,NULL,pDestStorage);
//
//									//// Commit changes to new stream
//									pDestStorage-> Commit(0);
//
//									// Release each of our streams
//									pDestStorage-> Release();
//								}
//
//							}
//
//						}
//
//						// Release the attachment
//						lpAttach -> Release();
//					}
//				}
//			}
//		}
//
//		FreeProws(pRows);
//
//		if (pAttTbl)
//			pAttTbl -> Release();
//	}
//Quit:
//	MAPIFreeBuffer((LPVOID) pProps);
//	return hRes;
//}

HRESULT SaveToRTF( LPMESSAGE pMessage, char *strFileName, HWND hWndRichEdit, LPSTREAM pUncompressedCompressedRTFStream )
{
	char *pBody=0;
	int nSize=0;

	////Compressed RTF stream
	LPSTREAM pCompressedRTFStream=NULL;
	LPRICHEDITOLE	pRichEditOle=NULL;
	LPSPropValue pProp = NULL;

	static SizedSPropTagArray(5,sptCols) = {5, PR_ATTACH_METHOD,PR_ATTACH_NUM,PR_RENDERING_POSITION, PROP_TAG(PT_STRING8,0x370E),PR_ATTACH_LONG_FILENAME};
	LPSRowSet pRows = NULL;
	HRESULT hRes; 
	if(pUncompressedCompressedRTFStream==NULL)
	{
		hRes = pMessage->OpenProperty(PR_RTF_COMPRESSED, &IID_IStream, STGM_READ, 0, (IUnknown**)&pCompressedRTFStream);

		if(FAILED(hRes))
			return hRes;
		hRes=WrapCompressedRTFStream(pCompressedRTFStream,0 ,&pUncompressedCompressedRTFStream); //STORE_UNCOMPRESSED_RTF
		if(FAILED(hRes))
			return hRes;
	}
#ifdef DEBUG


	// get subject line of message to copy. This will be used as the
	// new file name.
#endif
	ULONG cAttach=0;
	LPMAPITABLE pAttachments=NULL;
	hRes = pMessage->GetAttachmentTable(MAPI_UNICODE,&pAttachments) ;
	if(SUCCEEDED(hRes))
	{

		if(SUCCEEDED(pAttachments->GetRowCount(0,&cAttach)))
		{
			// This structure tells HrQueryAllRows what columns we want returned.

			if(FAILED(hRes=HrQueryAllRows(pAttachments,(SPropTagArray*)&sptCols,NULL,NULL,0,&pRows)))
			{
				return hRes;

			}
		}
	}


	BOOL EmbeddedObjects=FALSE;


	for(ULONG iAttach=0;iAttach<cAttach;iAttach++)
	{
		if(pRows->aRow[iAttach].lpProps[0].Value.ul==ATTACH_OLE)
		{
			EmbeddedObjects=TRUE;
			break;
		}
	}


	if(EmbeddedObjects)
	{
#ifdef DEBUG
		ShowWindow(hWndRichEdit,SW_SHOWNORMAL);
		ShowWindow(hWndRichEdit,SW_RESTORE);
#endif
		LPOLECLIENTSITE lpOleClientSite = NULL; 

		EDITSTREAM esIn;
		esIn.dwCookie = (DWORD)pUncompressedCompressedRTFStream;
		esIn.pfnCallback = MyStreamInCallback; 


		SendMessage(hWndRichEdit,EM_STREAMIN,SF_RTF,(LPARAM)&esIn); 

		LPATTACH lpAttach = NULL;
		SendMessage(hWndRichEdit, EM_GETOLEINTERFACE, 0, (LPARAM)&pRichEditOle);
		hRes=pRichEditOle->GetClientSite(&lpOleClientSite);
		if(FAILED(hRes))
		{
			MessageBox(NULL,"1","2",MB_OK);
			cAttach=0;
		}

		for(UINT iAttach=0;iAttach<cAttach;iAttach++)
		{
			if(pRows->aRow[iAttach].lpProps[0].Value.ul==ATTACH_OLE)
			{

				LPSTORAGE pStorage=NULL;
				LPSTORAGE pDestStorage=NULL;
				// Open the attachment
				if (SUCCEEDED(hRes = pMessage->OpenAttach (pRows->aRow[iAttach].lpProps[1].Value.l,NULL, MAPI_BEST_ACCESS, &lpAttach)))
				{
					// Open the property of the attachment
					// containing the file data
					if (SUCCEEDED(hRes = lpAttach->OpenProperty(PR_ATTACH_DATA_OBJ,(LPIID)&IID_IStorage,0,0,(LPUNKNOWN *)&pStorage)))
					{

						REOBJECT reobject; 
						DVASPECT dAspect=DVASPECT_CONTENT ;
						LPDATAOBJECT pData;
						LPPERSISTSTORAGE pPersistStorage=NULL;
						IEnumFORMATETC *pefEtc = 0;
						FORMATETC fEtc;
						STGMEDIUM StgMedium;
						LPOLEOBJECT pOle=NULL;
						STATSTG stg = {0};
						hRes = pStorage->Stat(&stg,STATFLAG_NONAME);
						LPLOCKBYTES lpLockBytes = NULL;

						if(SUCCEEDED(hRes= ::CreateILockBytesOnHGlobal(NULL, TRUE, &lpLockBytes)))
						{
							if(SUCCEEDED(hRes= ::StgCreateDocfileOnILockBytes(lpLockBytes,STGM_SHARE_EXCLUSIVE|STGM_CREATE|STGM_READWRITE, 0, &pDestStorage)))
							{
								if(IsEqualCLSID(stg.clsid,CLSID_StdOleLink))
								{
									//if(Log)
									//	MessageBox(NULL,"Link detected",strFileName,MB_OK);
									CLIPFORMAT cfFormat = 0;
									LPFORMATETC lpFormatEtc = NULL;
									// fill in FORMATETC struct
									FORMATETC formatEtc;
									lpFormatEtc = &formatEtc;
									lpFormatEtc->cfFormat = cfFormat;
									lpFormatEtc->ptd = NULL;
									lpFormatEtc->dwAspect = DVASPECT_CONTENT;
									lpFormatEtc->lindex = -1;
									lpFormatEtc->tymed = TYMED_NULL;
									hRes=ERROR_CALL_NOT_IMPLEMENTED;

									CLSID clsid = CLSID_NULL;
									OLERENDER render = OLERENDER_DRAW;

									hRes=OleLoad(pStorage,IID_IOleObject,lpOleClientSite, (LPVOID *)&pOle);
									if(SUCCEEDED(hRes))
									{

										hRes=pOle->QueryInterface(IID_IPersistStorage, (void**)&pPersistStorage);
										if(SUCCEEDED(hRes))
										{
											hRes=pPersistStorage->Save(pDestStorage,FALSE);
											hRes=pDestStorage->Commit(0);
											pPersistStorage->Release();
											pPersistStorage=NULL;
										}
									}
									else
									{
										char szError[1024];
										LPSTR sType;
										sType=(LPSTR)malloc(255);

										LPOLESTR pOleStr;
										StringFromCLSID(stg.clsid,&pOleStr);
										UnicodeToAnsi(pOleStr,&sType);
										CoTaskMemFree(pOleStr);
										wsprintf(szError,"Ole load failed when loading an object of type %s. Error: 0x%x",sType,hRes);
										free(sType);

#ifdef DEBUG
										MessageBox(NULL,szError,strFileName,MB_OK);
#endif
									}
									dAspect=DVASPECT_CONTENT;
								}
								else
								{

									//if(Log)
									//	MessageBox(NULL,"Object detected",strFileName,MB_OK);

									hRes = CoCreateInstance(stg.clsid, NULL, CLSCTX_INPROC_SERVER , IID_IPersistStorage, (LPVOID *)&pPersistStorage);
									if(SUCCEEDED(hRes))
									{
										hRes=pPersistStorage->Load(pStorage);
										if(SUCCEEDED(hRes))
										{
											hRes=pPersistStorage->Save(pDestStorage,FALSE);
											if(SUCCEEDED(hRes))
											{

												hRes=pDestStorage->Commit(0);
												if(SUCCEEDED(hRes))
												{

													hRes=pPersistStorage->QueryInterface(IID_IDataObject, (LPVOID *)&pData);

													if(SUCCEEDED(hRes))
													{

														LPFORMATETC lpFormatEtc = NULL; 
														FORMATETC formatEtc; 
														CLIPFORMAT cfFormat = 0; 

														lpFormatEtc = &formatEtc; 
														lpFormatEtc->cfFormat = cfFormat; 
														lpFormatEtc->ptd = NULL; 
														lpFormatEtc->dwAspect = DVASPECT_CONTENT; 
														lpFormatEtc->lindex = -1; 
														lpFormatEtc->tymed = TYMED_NULL; 

														hRes=OleQueryCreateFromData(pData);
														if(SUCCEEDED(hRes))
														{
															hRes=pData->GetData(&fEtc,&StgMedium);
															if(SUCCEEDED(hRes))
															{
																hRes=pPersistStorage->QueryInterface(IID_IOleObject, (LPVOID *)&pOle);
															}
														}


													}
												}
											}
										}
									}
									else
									{
#ifdef DEBUG
										//if(Log)
										//	MessageBox(NULL,"CoCreateInstance failed",strFileName,MB_OK);
#endif
									}

								}

								if(SUCCEEDED(hRes)&& pOle)
								{
									CLSID clsid;
									OleSetContainedObject(pOle, TRUE); 
									hRes = pOle->GetUserClassID(&clsid);

									reobject.clsid = clsid; 
									reobject.cp = REO_CP_SELECTION; 
									reobject.dvaspect = dAspect; 
									reobject.dwFlags = REO_DYNAMICSIZE;
									reobject.dwUser = 0; 
									reobject.poleobj = pOle; 
									reobject.polesite = lpOleClientSite; 

									reobject.pstg = pDestStorage; 

									SIZEL sizel; 
									DWORD dwStart, dwEnd; 


									sizel.cx = sizel.cy = 0; 
									reobject.sizel = sizel; 


									SendMessage(hWndRichEdit, EM_SETSEL, 0, -1); 
									SendMessage(hWndRichEdit, EM_GETSEL, (WPARAM)&dwStart, 	(LPARAM)&dwEnd); 
									dwEnd=pRows->aRow[iAttach].lpProps[2].Value.l;
									SendMessage(hWndRichEdit, EM_SETSEL, dwEnd+1, dwEnd+1); 
									hRes=pRichEditOle->InsertObject(&reobject);

									if(pPersistStorage)
										pPersistStorage->Release();
									if(pDestStorage)
										pDestStorage->Release();
									if(pOle)
										pOle->Release();

								}
							}//StgCreateDocfileOnILockBytes
						} //CreateILockBytesOnHGlobal
						if(pStorage)
							pStorage->Release();

					}
					lpAttach->Release();
				}
			}


		}
		if(pRichEditOle)
		{
			int objectCount = pRichEditOle->GetObjectCount();

			// 
			// Loop through each object in the control and if active
			// deactivate, and if open, close.
			// 
			for (int i = 0; i < objectCount; i++)
			{
				REOBJECT reObj;
				ZeroMemory(&reObj, sizeof(REOBJECT));
				reObj.cbStruct  = sizeof(REOBJECT);

				// 
				// Get the Nth object
				// 
				hRes = pRichEditOle->GetObject(i,&reObj,REO_GETOBJ_POLEOBJ);
				if(SUCCEEDED(hRes))
				{
					// 
					// If active, deactivate.
					// 
					if (reObj.dwFlags && REO_INPLACEACTIVE)
						pRichEditOle->InPlaceDeactivate();

					// 
					// If the object is open, close it.
					// 
					if(reObj.dwFlags&&REO_OPEN)
						hRes = reObj.poleobj->Close(OLECLOSE_NOSAVE);

					reObj.poleobj->Release();
				}
			}
			pRichEditOle->Release();
			pRichEditOle=NULL;

		}

		HANDLE hRTFFile; 

		hRTFFile= CreateFile(strFileName, // filename
			GENERIC_WRITE,									// open for writing 
			0,															// do not share 
			NULL,														// no security 
			CREATE_ALWAYS,									// overwrite existing 
			FILE_ATTRIBUTE_NORMAL,					// normal file 
			NULL);     							 
		EDITSTREAM es;

		struct Foo param;
		param.hFile=hRTFFile;
		es.dwCookie = (DWORD)&param;
		es.pfnCallback = MyStreamOutCallback; 

		SendMessage(hWndRichEdit,EM_STREAMOUT,SF_UNICODE|SF_USECODEPAGE|SF_RTF,(LPARAM)&es); 
		CloseHandle(hRTFFile);


	}
	else
	{
		HANDLE hRTFFile; 
		hRTFFile= CreateFile(strFileName, // filename
			GENERIC_WRITE,									// open for writing 
			0,															// do not share 
			NULL,														// no security 
			CREATE_ALWAYS,									// overwrite existing 
			FILE_ATTRIBUTE_NORMAL,					// normal file 
			NULL);     							 
		BYTE    rgBuffer[5000];
		ULONG   cb;


		LARGE_INTEGER li ={0,0};
		if(SUCCEEDED(pUncompressedCompressedRTFStream->Seek(li,STREAM_SEEK_SET,NULL)))
		{
			do 
			{
				pUncompressedCompressedRTFStream->Read(rgBuffer,    // Buffer to write the data
					sizeof(rgBuffer),   // Number of bytes to get
					&cb);   // Number of bytes written to buffer

				if (cb > 0)               
				{
					DWORD dw2=0;
					if(!WriteFile(hRTFFile,rgBuffer,cb,&dw2,NULL))
						return -1234;

				}
			} while (cb >= sizeof(rgBuffer));
		}

		CloseHandle(hRTFFile);
	}
	if(pCompressedRTFStream!=NULL)
		pCompressedRTFStream->Release();
	if(pRichEditOle)
		pRichEditOle->Release();
	//if(pCallback)
	//{
	//	pCallback->Release();
	//	delete pCallback;
	//}




	return hRes;

}
void decodertfhtml(char *buf,unsigned int *len);

HRESULT ConverttoHMTLAndWriteToFile(char *pBody,unsigned int size,HANDLE hFile)
{
	HRESULT hRes=0;
	DWORD dWritten;
	//DebugBreak();
	if(!strstr(pBody,"\\fromhtml"))
	{
		WriteFile(hFile,pBody ,size,&dWritten,NULL);
		return 1;
	}
	else
	{
#ifdef DEBUG

		//		MessageBox(NULL,pBody,"RTF",MB_OK);

#endif
		decodertfhtml(pBody,&size);
#ifdef DEBUG

		//		MessageBox(NULL,pBody,"HTML",MB_OK);

#endif
		WriteFile(hFile,pBody ,size,&dWritten,NULL);
	}
	return NOERROR;
} 


//
//
// http://www.wischik.com/lu/programmer/mapi_utils.html
//


void decodertfhtml(char *buf,unsigned int *len)
{ // c -- pointer to where we're reading from
	// d -- pointer to where we're writing to. Invariant: d<c
	// max -- how far we can read from (i.e. to the end of the original rtf)
	// ignore_tag -- stores 'N': after \mhtmlN, we will ignore the subsequent \htmlN.
	char *c=buf, *max=buf+*len, *d=buf; int ignore_tag=-1;
	// First, we skip forwards to the first \htmltag.
	while (c<max && strncmp(c,"{\\*\\htmltag",11)!=0) c++;
	//
	// Now work through the document. Our plan is as follows:
	// * Ignore { and }. These are part of RTF markup.
	// * Ignore \htmlrtf...\htmlrtf0. This is how RTF keeps its equivalent markup separate from the html.
	// * Ignore \r and \n. The real carriage returns are stored in \par tags.
	// * Ignore \pntext{..} and \liN and \fi-N. These are RTF junk.
	// * Convert \par and \tab into \r\n and \t
	// * Convert \'XX into the ascii character indicated by the hex number XX
	// * Convert \{ and \} into { and }. This is how RTF escapes its curly braces.
	// * When we get \*\mhtmltagN, keep the tag, but ignore the subsequent \*\htmltagN
	// * When we get \*\htmltagN, keep the tag as long as it isn't subsequent to a \*\mhtmltagN
	// * All other text should be kept as it is.
	while (c<max)
	{ 
		if (*c=='{') 
			c++;
		else if (*c=='}') 
			c++;
		else if (strncmp(c,"\\htmlbase",9)==0)
		{ 
			c+=9;
			if (*c==' ') 
				c++;
		}


		else if (strncmp(c,"\\*\\htmltag",10)==0)
		{ 
			c+=10; 
			int tag=0; 
			while (*c>='0' && *c<='9') 
			{
				tag=tag*10+*c-'0'; c++;
			}
			if (*c==' ') 
				c++;
			if (tag==ignore_tag) 
			{
				while (c<max && *c!='}') 
					c++; 
				if (*c=='}') 
					c++;
			}
			ignore_tag=-1;
		}
		else if (strncmp(c,"\\*\\mhtmltag",11)==0)
		{ 
			c+=11; 
			int tag=0; 
			while (*c>='0' && *c<='9') 
			{
				tag=tag*10+*c-'0'; 
				c++;
			}
			if (*c==' ') 
				c++;
			ignore_tag=tag;
		}
		else if (strncmp(c,"\\par",4)==0) 
		{
			strcpy(d,"\r\n"); 
			d+=2; 
			c+=4; 
			if (*c==' ') 
				c++;
		}
		else if (strncmp(c,"\\tab",4)==0) 
		{
			strcpy(d,"   "); 
			d+=3; 
			c+=4; 
			if (*c==' ') 
				c++;
		}
		else if (strncmp(c,"\\li",3)==0)
		{ 
			c+=3; 
			while (*c>='0' && *c<='9') 
				c++; 
			if (*c==' ') 
				c++;
		}
		else if (strncmp(c,"\\fi-",4)==0)
		{ 
			c+=4; 
			while (*c>='0' && *c<='9') 
				c++; 
			if (*c==' ') 
				c++;
		}
		else if (strncmp(c,"\\'",2)==0)
		{ 
			unsigned int hi=c[2], lo=c[3];
			if (hi>='0' && hi<='9') 
				hi-='0'; 
			else if (hi>='A' && hi<='Z') 
				hi=hi-'A'+10; 
			else if (hi>='a' && hi<='z') 
				hi=hi-'a'+10;
			if (lo>='0' && lo<='9') 
				lo-='0'; 
			else if (lo>='A' && lo<='Z') 
				lo=lo-'A'+10; 
			else if (lo>='a' && lo<='z') 
				lo=lo-'a'+10;
			*((unsigned char*)d) = (unsigned char)(hi*16+lo);
			c+=4; d++;
		}
		else if (strncmp(c,"\\pntext",7)==0) 
		{
			c+=7; 
			while (c<max && *c!='}') 
				c++;
		}
		else if (strncmp(c,"\\htmlrtf",8)==0)
		{ 
			c++; 
			while (c<max && strncmp(c,"\\htmlrtf0",9)!=0) 
				c++;
			if (c<max) 
				c+=9; 
			if (*c==' ') 
				c++;
		}
		else if (*c=='\r' || *c=='\n') 
			c++;
		else if (strncmp(c,"\\{",2)==0) 
		{
			*d='{'; 
			d++; 
			c+=2;
		}
		else if (strncmp(c,"\\}",2)==0) 
		{
			*d='}'; 
			d++; 
			c+=2;
		}
		else 
		{
			*d=*c; 
			c++; 
			d++;
		}
	}

	*d=0;
	d++;
	*len = (unsigned int)(d-buf);
}




HRESULT SaveToHTML( LPMESSAGE pMessage, char *strFileName, LPSTREAM pUncompressedStream )
{

	char *pBody=0;
	HRESULT hRes;
	int nSize=0;
	unsigned long bufsize=10240;
	unsigned long allocatedsize=0;
	pBody = new char[bufsize];
	bool done=false;
	HANDLE hFile; 
	hFile = CreateFile(strFileName,
		GENERIC_WRITE,                // open for writing 
		0,                            // do not share 
		NULL,                         // no security 
		CREATE_ALWAYS,                // overwrite existing 
		FILE_ATTRIBUTE_NORMAL,        // normal file 
		NULL);                        // no attr. template 
	if(hFile != INVALID_HANDLE_VALUE)
	{
		//DebugBreak();
		while (!done)  
		{ 
			ULONG red; 
			hRes = pUncompressedStream->Read(pBody+allocatedsize , bufsize , &red);
			if(!red)
				break;
			if (SUCCEEDED(hRes))
			{
				allocatedsize+=red;
				done = (red < bufsize);
				if(!done)
				{
					char *pNewBody=new char[bufsize+allocatedsize];
					if(pNewBody)
					{
						memcpy(pNewBody,pBody,allocatedsize);
						delete [] pBody;
						pBody=pNewBody;
					}
				}
				else
				{
					pBody[allocatedsize]='\0';
					break;
				}



			}
			else
			{
				pBody[allocatedsize]='\0';
				done=true;
			}
		}
		hRes=ConverttoHMTLAndWriteToFile(pBody,allocatedsize,hFile);
		delete [] pBody;
		CloseHandle(hFile);


	}
	return hRes;

}



HRESULT SaveToMSG ( LPMESSAGE pMessage, char *strAttachmentFile )
{
	HRESULT hRes = S_OK;
	LPSPropValue pSubject = NULL;
	LPSTORAGE pStorage = NULL;
	LPMSGSESS pMsgSession =  NULL;
	LPMESSAGE pIMsg = NULL;
	SizedSPropTagArray ( 7, excludeTags );
	char szPath[_MAX_PATH];

	LPWSTR lpWideCharStr = NULL;
	ULONG cbStrSize = 0L;

	// create the file name in the directory where "TMP" is defined
	// with subject as the filename and ".msg" extension.

	// get temp file directory
	GetTempPath(_MAX_PATH, szPath);

	// get subject line of message to copy. This will be used as the
	// new file name.
	HrGetOneProp( pMessage, PR_SUBJECT, &pSubject );


	// get memory allocation function
	LPMALLOC pMalloc = MAPIGetDefaultMalloc();

	// Convert new file name to WideChar
	cbStrSize = MultiByteToWideChar (CP_ACP,
		MB_PRECOMPOSED,
		strAttachmentFile,
		-1, lpWideCharStr, 0);

	MAPIAllocateBuffer ( cbStrSize * sizeof(WCHAR),
		(LPVOID *)&lpWideCharStr );

	MultiByteToWideChar (CP_ACP,
		MB_PRECOMPOSED,
		strAttachmentFile,
		-1, lpWideCharStr, cbStrSize );

	// create compound file
	hRes = ::StgCreateDocfile(lpWideCharStr,
		STGM_READWRITE |
		STGM_TRANSACTED |
		STGM_CREATE, 0, &pStorage);

	if(SUCCEEDED(hRes))
	{

		// Open an IMessage session.
		hRes = ::OpenIMsgSession(pMalloc, 0, &pMsgSession);
		if(SUCCEEDED(hRes))
		{

			// Open an IMessage interface on an IStorage object
			hRes = ::OpenIMsgOnIStg(pMsgSession,
				MAPIAllocateBuffer,
				MAPIAllocateMore,
				MAPIFreeBuffer,
				pMalloc,
				NULL,
				pStorage,
				NULL, 0, 0, &pIMsg);
			if(SUCCEEDED(hRes))
			{

				// write the CLSID to the IStorage instance - pStorage. This will
				// only work with clients that support this compound document type
				// as the storage medium. If the client does not support
				// CLSID_MailMessage as the compound document, you will have to use
				// the CLSID that it does support.
				hRes = WriteClassStg(pStorage, CLSID_MailMessage );

				// Specify properties to exclude in the copy operation. These are
				// the properties that Exchange excludes to save bits and time.
				// Should not be necessary to exclude these, but speeds the process
				// when a lot of messages are being copied.
				excludeTags.cValues = 7;
				excludeTags.aulPropTag[0] = PR_ACCESS;
				excludeTags.aulPropTag[1] = PR_BODY;
				excludeTags.aulPropTag[2] = PR_RTF_SYNC_BODY_COUNT;
				excludeTags.aulPropTag[3] = PR_RTF_SYNC_BODY_CRC;
				excludeTags.aulPropTag[4] = PR_RTF_SYNC_BODY_TAG;
				excludeTags.aulPropTag[5] = PR_RTF_SYNC_PREFIX_COUNT;
				excludeTags.aulPropTag[6] = PR_RTF_SYNC_TRAILING_COUNT;

				// copy message properties to IMessage object opened on top of
				// IStorage.
				hRes = pMessage->CopyTo(0, NULL,
					(LPSPropTagArray)&excludeTags,
					NULL, NULL,
					(LPIID)&IID_IMessage,
					pIMsg, 0, NULL );
				if(SUCCEEDED(hRes))
				{

					// save changes to IMessage object.
					if(SUCCEEDED(pIMsg -> SaveChanges ( KEEP_OPEN_READWRITE )))
						hRes = pStorage -> Commit(STGC_DEFAULT);				// save changes in storage of new doc file
				}

				// free objects and clean up memory
				MAPIFreeBuffer ( lpWideCharStr );
				pIMsg->Release();
			}
			CloseIMsgSession ( pMsgSession );
		}
		pStorage->Release();
	}

	pStorage = NULL;
	pIMsg = NULL;
	pMsgSession = NULL;
	lpWideCharStr = NULL;

	return hRes;
}


HRESULT SaveToMIME ( LPMESSAGE pMessage, char *szFilename,  int ulFlags)
{
	if(SUCCEEDED(fnIsMIMEConversionSupported()))
	{
		HRESULT hRes = S_OK;
		LPCONVERTERSESSION pConverter = NULL;

		hRes = CoCreateInstance(
			CLSID_IConverterSession,
			NULL,
			CLSCTX_INPROC_SERVER,
			IID_IConverterSession,
			(LPVOID *)&pConverter
			);

		if(SUCCEEDED(hRes))
		{
			pConverter->SetTextWrapping(false,0);
			pConverter->SetEncoding(IET_8BIT);
			LPSTREAM pStream=NULL;
			if(SUCCEEDED(CreateStreamOnHGlobal(NULL, TRUE, &pStream)))
			{
				HANDLE hFile=NULL;
				hFile=CreateFile(szFilename,GENERIC_WRITE,0,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL);

				if (hFile != INVALID_HANDLE_VALUE) 
				{ 

					if(SUCCEEDED(pConverter->MAPIToMIMEStm(pMessage,pStream,ulFlags)))
					{
						// Read and process 5000 bytes at a time.
						BYTE    rgBuffer[5000];
						ULONG   cb;

						LARGE_INTEGER li ={0,0};
						if(SUCCEEDED(pStream->Seek(li,STREAM_SEEK_SET,NULL)))
						{
							do 
							{
								pStream->Read(rgBuffer,    // Buffer to write the data
									sizeof(rgBuffer),   // Number of bytes to get
									&cb);   // Number of bytes written to buffer

								if (cb > 0)               
								{
									DWORD dw2=0;
									if(!WriteFile(hFile,rgBuffer,cb,&dw2,NULL))
										return WRITEFILEFAILED;

								}
							} while (cb >= sizeof(rgBuffer));
							CloseHandle(hFile);
						}

					}


					pStream->Release();
				}
				else
					return CREATEFILEFAILED;


			}
			else
				return COULDNOTCREATESTREAM;
			pConverter->Release();



		}


	}
	else
		return NOMIMESUPPORT;
	return 0;
}



int fnGetMHTML(LPMESSAGE pMessage, LPSTR szDir, LPSTR szFileName, LPSTREAM pUncompressedStream);

int fnExportMailMessage(LPUNKNOWN pMessage, char *szFileName, int nExportAs, HWND hWnd, char *szTempFolder,int *FileType)
{
	LPMESSAGE pMessagePtr;
	*FileType=nExportAs;
	LPSTREAM pCompressedRTFStream=NULL;
	LPSTREAM pUnCompressedRTFStream=NULL;
	unsigned long bufsize=1240;
	unsigned long allocatedsize=0;
	char *pBody;
	pBody = new char[bufsize];

	HRESULT hRes=pMessage->QueryInterface(IID_IMessage,(LPVOID *)&pMessagePtr);
	if(SUCCEEDED(hRes))
	{
		if(nExportAs==1)
		{
			hRes = pMessagePtr->OpenProperty(PR_RTF_COMPRESSED, &IID_IStream, STGM_READ, 0, (IUnknown**)&pCompressedRTFStream);

			if(SUCCEEDED(hRes))
			{
				hRes=WrapCompressedRTFStream(pCompressedRTFStream,0 ,&pUnCompressedRTFStream); //STORE_UNCOMPRESSED_RTF
				if(FAILED(hRes))
					return -1;
				pUnCompressedRTFStream->Read(pBody,bufsize,&allocatedsize);
				LARGE_INTEGER li ={0,0};
				pUnCompressedRTFStream->Seek(li,STREAM_SEEK_SET,NULL);

				if(strstr(pBody,"\\fromhtml"))
				{
					*FileType=0;
					if(nExportAs!=5)
						nExportAs=0;
				}
				delete []pBody;
			}
		}


		switch(nExportAs)
		{
		case 0:
			//DebugBreak();
			{
				char *p=strrchr(szFileName,'\\');
				if(p)
				{
					*p++;

					hRes=fnGetMHTML(pMessagePtr, szTempFolder,p,pUnCompressedRTFStream);
				}
				else
				{
					hRes=fnGetMHTML(pMessagePtr, szTempFolder,szFileName,pUnCompressedRTFStream);
				}

				//hRes=SaveToHTML( pMessagePtr, szFileName,pUnCompressedRTFStream );
				break;
			}
		case 1:
			{
				char szFile[MAX_PATH];
				strcpy(szFile,szFileName);
				if(!strstr(szFile,".rtf"))
					strcat(szFile,".rtf");

				hRes=SaveToRTF ( pMessagePtr, szFile, hWnd,pUnCompressedRTFStream);
			}

			break;
		case 2:
			hRes=SaveToMSG ( pMessagePtr, szFileName );
			break;
		case 3:
			hRes=SaveToTxt ( pMessagePtr, szFileName );
			break;
		case 5:
			//DebugBreak();
			hRes=SaveToHTML( pMessagePtr, szFileName,pUnCompressedRTFStream );
			break;
		}
		if(pUnCompressedRTFStream)
			pUnCompressedRTFStream->Release();
		if(pCompressedRTFStream)
			pCompressedRTFStream->Release();
		pMessagePtr->Release();
	}
	if(SUCCEEDED(hRes))
		return 0;
	else
	{
		int RetValue=EXPORTMAILMESSAGEFAILED;
		if(hRes==0x80040154)
		{
			RetValue=EXPORTEDWITHOLEERRORS;
		}
		else if(hRes==0x80040068)
		{
			RetValue=EXPORTEDWITHOLEERRORS;
		}
		else
		{
#ifdef DEBUG
			char szError[MAX_PATH];

			wsprintf(szError,"Error 0x%x when saving file %s",hRes,szFileName);
			MessageBox(NULL,szError,"Error",MB_OK);
#endif
		}
		return RetValue;
	}
}

int fnConvertMailMessageToMIME(LPVOID pObject, char *szFilename, int ulFlags)
{
	return SaveToMIME ( (LPMESSAGE) pObject, szFilename, ulFlags );
}
int fnIsMIMEConversionSupported()
{
	//Check using CoCreateInstance for existance of MIMEConverter
	HRESULT hRes = S_OK;
	LPCONVERTERSESSION pConverter = NULL;

	hRes = CoCreateInstance(
		CLSID_IConverterSession,
		NULL,
		CLSCTX_INPROC_SERVER,
		IID_IConverterSession,
		(LPVOID *)&pConverter
		);
	pConverter->Release();


	return hRes;
}
struct recurrenctInfo {
	int len;
	int array[256];
};
int fnGetRecurrencyPattern(LPUNKNOWN pObject, recurrenctInfo *pRecurrenctInfo, unsigned int *IsRecurring, unsigned int *RecurrenceData)
{
	int returnvalue=-1;
	LPMESSAGE pMessagePtr;

	HRESULT hr=pObject->QueryInterface(IID_IMessage,(LPVOID *)&pMessagePtr);
	if(SUCCEEDED(hr))
	{
		if(*IsRecurring==0)
		{
			LPSPropTagArray lpNamedPropTags = NULL;

			LPMAPINAMEID ppNames[2]={0};
			MAPINAMEID NamedProp1={0};
			NamedProp1.lpguid = (LPGUID)&CLSID_EVENT;
			NamedProp1.ulKind = MNID_ID;
			NamedProp1.Kind.lID = 0x8216;
			ppNames[0]=&NamedProp1;

			MAPINAMEID NamedProp2={0};
			NamedProp2.lpguid = (LPGUID)&CLSID_EVENT;
			NamedProp2.ulKind = MNID_ID;
			NamedProp2.Kind.lID = 0x8223;
			ppNames[1]=&NamedProp2;

			MAPINAMEID NamedID = {0};
			LPMAPINAMEID lpNamedID = &NamedID;
			hr=pMessagePtr->GetIDsFromNames(2,ppNames,0,&lpNamedPropTags);
			if(SUCCEEDED(hr))
			{
				*RecurrenceData=CHANGE_PROP_TYPE(lpNamedPropTags->aulPropTag[0],PT_BINARY);
				*IsRecurring=CHANGE_PROP_TYPE(lpNamedPropTags->aulPropTag[1],PT_BOOLEAN);
			}
		}


		LPSPropValue pProp = NULL;
		if(SUCCEEDED(HrGetOneProp( pMessagePtr, *IsRecurring, &pProp)))
		{
			if(pProp->Value.b==TRUE)
			{
				if(SUCCEEDED(HrGetOneProp(pMessagePtr,  *RecurrenceData, &pProp)))
				{
					LPSPropTagArray lpNamedPropTags = NULL;


					if(pProp->Value.bin.cb>0)
					{
						int i=0;
						pRecurrenctInfo->len=pProp->Value.bin.cb;
						for(i=0;i<=pRecurrenctInfo->len;i++)
						{
							pRecurrenctInfo->array[i]=pProp->Value.bin.lpb[i];
						}

						//memcpy(pRecurrenctInfo->array,pProp->Value.bin.lpb,pProp->Value.bin.cb);
						returnvalue=pProp->Value.bin.cb;
					}

				}
			}
		}
		pMessagePtr->Release();            



	}
	return returnvalue;
}
int fnGetMHTML(LPMESSAGE pMessagePtr, LPSTR szDirectory,LPSTR szFileNameInput, LPSTREAM pUnCompressedRTFStream)
{
	int returnvalue=0;
	HRESULT hr=NOERROR;

	LPSRowSet pRows = NULL;
	char szFileName[MAX_PATH];
	strcpy(szFileName,szDirectory);
	strcat(szFileName,"\\");
	strcat(szFileName,szFileNameInput);
	strcat(szFileName,".htm");
	if(0==SaveToHTML(pMessagePtr,szFileName,pUnCompressedRTFStream))
	{
		ULONG cAttach=0;
		LPMAPITABLE pAttachments=NULL;
		HRESULT hRes = pMessagePtr->GetAttachmentTable(MAPI_UNICODE,&pAttachments) ;
		static SizedSPropTagArray(5,sptCols) = {5, PR_ATTACH_METHOD,PR_ATTACH_NUM,PR_RENDERING_POSITION, PROP_TAG(PT_STRING8,0x370E),PR_ATTACH_LONG_FILENAME};
		if(SUCCEEDED(hRes))
		{

			if(SUCCEEDED(pAttachments->GetRowCount(0,&cAttach)))
			{
				// This structure tells HrQueryAllRows what columns we want returned.

				if(FAILED(hRes=HrQueryAllRows(pAttachments,(SPropTagArray*)&sptCols,NULL,NULL,0,&pRows)))
				{
					return hRes;

				}
			}
			LPATTACH lpAttach = NULL;
			for(int iAttach=0;iAttach<cAttach;iAttach++)
			{
				if(pRows->aRow[iAttach].lpProps[3].Value.l!=MAPI_E_NOT_FOUND)
				{
					if(strncmp(pRows->aRow[iAttach].lpProps[3].Value.lpszA,"image/",6)==0)
					{
						LPSTORAGE pStorage=NULL;
						// Open the attachment
						if (SUCCEEDED(hRes = pMessagePtr->OpenAttach (pRows->aRow[iAttach].lpProps[1].Value.l,NULL, MAPI_BEST_ACCESS, &lpAttach)))
						{
							LPSTREAM pStrmSrc = NULL, pStrmDest = NULL;
							if (SUCCEEDED(hRes = lpAttach->OpenProperty(PR_ATTACH_DATA_BIN,(LPIID)&IID_IStream,0,MAPI_MODIFY,(LPUNKNOWN *)&pStrmSrc)))
							{
								STATSTG stg = {0};
								hRes = pStrmSrc->Stat(&stg,STATFLAG_NONAME);

								// Open an IStream interface and create the file at the
								// same time. This code will create the file in the
								// current directory.
								char szFileName2[MAX_PATH];
								strcpy(szFileName2,szDirectory);
								strcat(szFileName2,"\\");
								strcat(szFileName2,pRows->aRow[iAttach].lpProps[4].Value.lpszA);
								if (FAILED(hRes = OpenStreamOnFile(
									MAPIAllocateBuffer,
									MAPIFreeBuffer,
									STGM_CREATE | STGM_READWRITE,
									szFileName2,
									NULL,
									&pStrmDest)))
									break;


								hRes = pStrmSrc -> CopyTo(pStrmDest,
									stg.cbSize,
									NULL,
									NULL);

								// Commit changes to new stream
								pStrmDest -> Commit(0);

								// Release each of our streams
								pStrmDest -> Release();
								pStrmSrc -> Release();
								lpAttach->Release();
							}

						}
					}
				}
			}


			pAttachments->Release();
		}

	}


	return returnvalue;

}

int fnGetIdsFromNames(LPUNKNOWN pObject, LPWSTR name, int Type)
{
	int returnvalue=0;
	LPMESSAGE pMessagePtr;
	HRESULT hr=pObject->QueryInterface(IID_IMessage,(LPVOID *)&pMessagePtr);
	if(SUCCEEDED(hr))
	{
		LPMAPINAMEID ppNames[1]={0};
		MAPINAMEID NamedProp1={0};
		NamedProp1.lpguid=(LPGUID)&CLSID_OUTLOOKSET;
		NamedProp1.ulKind=MNID_STRING;
		NamedProp1.Kind.lpwstrName=name;
		ppNames[0]=&NamedProp1;
		LPSPropTagArray pPropTags= NULL;
		hr=pMessagePtr->GetIDsFromNames(1,ppNames,0,&pPropTags);
		if(SUCCEEDED(hr))
		{
			returnvalue=CHANGE_PROP_TYPE(pPropTags->aulPropTag[0],Type);
		}
		pMessagePtr->Release();
	}
	return returnvalue;

}
int fnCreateRTWindow()
{
	HWND hWnd=CreateWindowEx(0,RICHEDIT_CLASS, NULL, ES_MULTILINE, 10,10,500,800, NULL,NULL,GetModuleHandle(NULL),NULL); 
	SETTEXTEX ste;
	ste.flags = ST_DEFAULT;
	ste.codepage = 1200; // (Unicode code page), 
	SendMessage(hWnd, EM_SETTEXTEX, (WPARAM)&ste, (LPARAM)"");


	return (int)hWnd;
}
int fnDeleteRTWindow(int hWnd)
{
	CloseWindow((HWND)hWnd);
	DestroyWindow((HWND)hWnd);

	return 0;
}


//int fnSaveAttachments(LPUNKNOWN pMessage, char *szFileName, int id)
//{
//	LPMESSAGE pMessagePtr;
//
//	HRESULT hRes=pMessage->QueryInterface(IID_IMessage,(LPVOID *)&pMessagePtr);
//	if(SUCCEEDED(hRes))
//	{
//		LPATTACH lpAttach;
//		LPSTORAGE pStorage;
//		LPSTORAGE pDestStorage;
//		if(SUCCEEDED(hRes = pMessagePtr->OpenAttach (id,NULL, MAPI_BEST_ACCESS, &lpAttach)))
//		{
//			if (SUCCEEDED(hRes = lpAttach->OpenProperty(PR_ATTACH_DATA_OBJ,(LPIID)&IID_IStorage,0,MAPI_MODIFY,(LPUNKNOWN *)&pStorage)))
//			{
//				if(SUCCEEDED(hRes = StgCreateDocfile(L"C:\\1.msg",STGM_TRANSACTED|STGM_READWRITE|STGM_SHARE_EXCLUSIVE|STGM_CREATE,0,&pDestStorage)))
//					{
//						pStorage->CopyTo(0,NULL,NULL,pDestStorage);
//						pDestStorage->Commit(0);
//						pDestStorage->Release();
//
//					}
//				pStorage->Release();
//			}
//			else
//			{
//			if (SUCCEEDED(hRes = lpAttach->OpenProperty(PR_ATTACH_DATA_BIN,(LPIID)&IID_IStorage,0,MAPI_MODIFY,(LPUNKNOWN *)&pStorage)))
//			{
//				LPOLESTR lpFileNameStr;
//				AnsiToUnicode(szFileName,&lpFileNameStr);
//				if(SUCCEEDED(hRes = StgCreateDocfile(lpFileNameStr,STGM_TRANSACTED|STGM_READWRITE|STGM_SHARE_EXCLUSIVE|STGM_CREATE,0,&pDestStorage)))
//					{
//						pStorage->CopyTo(0,NULL,NULL,pDestStorage);
//						pDestStorage->Commit(0);
//						pDestStorage->Release();
//
//					}
//				pStorage->Release();
//			}
//			}
//			lpAttach->Release();
//			
//		}
//	}
//	return 0;
//
//}

// This is the constructor of a class that has been exported.
// see MAPIWrapper.h for the class definition
CMAPIWrapper::CMAPIWrapper()
{ 
	return; 
}

